package org.shell.commands;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import org.shell.commands.exceptions.CommandException;

public class CommandInvoker {

    private static HashMap<String, Object> instances = new HashMap<String, Object>();

    public static Object invoke(ShellCommand command, Object[] parameters) throws CommandException {
        try {
            Object instance = getInstance(command);
            Method method = command.getMethodInstance();
            if (method.isVarArgs()) {
                int paramsCount = method.getParameterTypes().length;
                Object[] p1 = Arrays.copyOf(parameters, paramsCount);
                String[] p2 = new String[parameters.length - paramsCount + 1];
                for(int i = 0 ; i < p2.length ; i++) {
                    p2[i] = (String) parameters[paramsCount - 1 + i];
                }
                p1[paramsCount - 1] = p2;
                return command.getMethodInstance().invoke(instance, p1);
            } else {
                return command.getMethodInstance().invoke(instance, parameters);
            }
        } catch (Exception e) {
            throw new CommandException("Can't invoke: "
                    + command.getClassName() + "."
                    + command.getMethodName()
                    + "(" + Arrays.deepToString(parameters) + ")" + "\n"
                    + "original message: " + e.getMessage());
        }
    }

    public static void removeAllInstances() {
        instances.clear();
    }

    public static void removeInstance(String className) {
        instances.remove(className);
    }

    public static String[] showInstances() {
        return instances.keySet().toArray(new String[]{});
    }

    public static Object getInstance(ShellCommand command) throws InstantiationException, IllegalAccessException {
        return getInstance(command.getClassInstance(), command.isStaticMethod());
    }

    public static Object getInstance(Class classInstance, Boolean isStatic) throws InstantiationException, IllegalAccessException {
        Object instance = null;
        instance = instances.get(classInstance.getCanonicalName());
        if (instance == null != isStatic) {
            instance = classInstance.newInstance();
            instances.put(classInstance.getCanonicalName(), instance);
        }
        return instance;
    }

    public static void remove(String name) {
        instances.remove(name);
    }
}
